package main

import "fmt"

//组合结构的方法集有如下规则：
//若类型 S 包含匿名字段 T，则 S 的方法集包含 T 的方法集。
//若类型 S 包含匿名字段 *T，则 S 的方法集包含 T 和 *T 方法集。
//不管类型 S 中嵌入的匿名字段是 T 还是*T，*S 方法集总是包含 T 和 *T 方法集。

//由于go的编译器会对方法调用进行转换 所以现在使用实例调用这些方法以及不会出现无法调用的情况了(是因为go语言编译器自动转换)
//通过本demo的测试 我们应当在以后编写代码中遵守该规则
type notifier interface {
	notify()
}

type user struct {
	name  string
	email string
}

func (u *user) notify() {
	fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)
}

func main() {
	u := user{"Bill", "bill@email.com"}
	//使用表达式 method expression 来验证(防止出现调用者调用的情况)
	mValue := u.notify //这个是 method Value 会隐式地传递receiver 即这里的实例u
	//这里会隐式传递 receiver
	mValue()
	//由于要测试 所以需要显示传递receiver
	mExpression := (*user).notify //method expression 需要显示地传入receiver 因为这里没有指定实例
	//mExpression(u) 这里会检验报错 因为实际上在u的方法集中是没有notify方法的 &u则有
	mExpression(&u)
	me := user.notify //创建一个只有值接收者的表达式
	me(u)             //这里没有检查异常 而是一个运行时异常 因为u的方法集没有notify方法
}
